/*
 * Copyright (C) 2014 Andrey Kulikov (andkulikov@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.transitionseverywhere.utils;


import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.utils.Matrix;
import ohos.agp.utils.Rect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ViewUtils {

    static class BaseViewUtils {

        private static final Field FIELD_VIEW_FLAGS =
                ReflectionUtils.getPrivateField(Component.class, "mViewFlags");

        private static final Field FIELD_LAYOUT_PARAMS =
                ReflectionUtils.getPrivateField(Component.class, "mLayoutConfig");

        private static final int VIEW_VISIBILITY_MASK = 0x0000000C;

        private static final Method METHOD_SET_FRAME =
                ReflectionUtils.getPrivateMethod(Component.class, "setFrame", int.class, int.class,
                        int.class, int.class);

        public float getTransitionAlpha(Component v) {
            return v.getAlpha();
        }

        public boolean isLaidOut(Component v, boolean defaultValue) {
            return defaultValue;
        }

        public void setClipBounds(Component v, Rect clipBounds) {
        }

        public Rect getClipBounds(Component v, Rect rect) {
            return null;
        }

        public void setTransitionName(Component v, String name) {
            v.setName(name);
        }

        public String getTransitionName(Component v) {
            return null;
        }

        public void setTranslationZ(Component view, float z) {
            // do nothing
        }

        public float getTranslationZ(Component view) {
            return 0;
        }

        public Component addGhostView(Component view, ComponentContainer viewGroup, Matrix matrix) {
            return null;
        }

        public void removeGhostView(Component view) {
            // do nothing
        }

        public void transformMatrixToGlobal(Component view, Matrix matrix) {
        }

        public void transformMatrixToLocal(Component v, Matrix matrix) {
        }

        public void setAnimationMatrix(Component view, Matrix matrix) {
        }

        public Object getWindowId(Component view) {
            return null;
        }

        public boolean isRtl(Component view) {
            return false;
        }

        public void setHasTransientState(Component view, boolean hasTransientState) {
        }

        public boolean hasTransientState(Component view) {
            return false;
        }

        public void setTransitionVisibility(Component v, int visibility) {
            int value = (Integer) ReflectionUtils.getFieldValue(v, 0, FIELD_VIEW_FLAGS);
            value = (value & ~VIEW_VISIBILITY_MASK) | visibility;
            ReflectionUtils.setFieldValue(v, FIELD_VIEW_FLAGS, value);
        }

        public void setLeftTopRightBottom(Component v, int left, int top, int right, int bottom) {
            ReflectionUtils.invoke(v, null, METHOD_SET_FRAME, left, top, right, bottom);
        }

        public void setLayoutParamsSilently(Component view, ComponentContainer.LayoutConfig layoutParams) {
            ReflectionUtils.setFieldValue(view, FIELD_LAYOUT_PARAMS, layoutParams);
        }

    }
    private static final BaseViewUtils IMPL;

    static {
        IMPL = new BaseViewUtils();
    }

    public static float getTransitionAlpha(Component v) {
        return IMPL.getTransitionAlpha(v);
    }

    public static boolean isLaidOut(Component v, boolean defaultValue) {
        return IMPL.isLaidOut(v, defaultValue);
    }

    public static Rect getClipBounds(Component v,Rect rect) {
        return IMPL.getClipBounds(v, rect);
    }

    public static String getTransitionName(Component v) {
        return IMPL.getTransitionName(v);
    }


    public static void transformMatrixToGlobal(Component view, Matrix matrix) {
        IMPL.transformMatrixToGlobal(view, matrix);
    }

    public static void transformMatrixToLocal(Component view, Matrix matrix) {
        IMPL.transformMatrixToLocal(view, matrix);
    }

    public static void setAnimationMatrix(Component view, Matrix matrix) {
        IMPL.setAnimationMatrix(view, matrix);
    }

    public static Component addGhostView(Component view, ComponentContainer viewGroup, Matrix matrix) {
        return IMPL.addGhostView(view, viewGroup, matrix);
    }

    public static void removeGhostView(Component view) {
        IMPL.removeGhostView(view);
    }

    public static Object getWindowId(Component view) {
        return IMPL.getWindowId(view);
    }

    public static boolean isRtl(Component view) {
        return IMPL.isRtl(view);
    }

    public static boolean hasTransientState(Component view) {
        return IMPL.hasTransientState(view);
    }

    public static void setHasTransientState(Component view, boolean hasTransientState) {
        IMPL.setHasTransientState(view, hasTransientState);
    }
    /**
     * Change the visibility of the View without triggering any other changes. This is
     * important for transitions, where visibility changes should not adjust focus or
     * trigger a new layout. This is only used when the visibility has already been changed
     * and we need a transient value during an animation. When the animation completes,
     * the original visibility value is always restored.
     *
     * @param visibility One of View.VISIBLE, View.INVISIBLE, or View.GONE.
     */
     public static void setTransitionVisibility(Component view, int visibility) {
        IMPL.setTransitionVisibility(view, visibility);
    }

    public static void setLeftTopRightBottom(Component view, int left, int top, int right, int bottom) {
        if (view != null) {
            IMPL.setLeftTopRightBottom(view, left, top, right, bottom);
        }
    }

    //needed
    public static void setLayoutParamsSilently(Component view, ComponentContainer.LayoutConfig layoutParams) {
        IMPL.setLayoutParamsSilently(view, layoutParams);
    }
}
